#ifndef __OPENCLMANAGER_H__
#define __OPENCLMANAGER_H__

#include "OpenCLGL_Util.h"
#include "CL/cl.hpp"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <fstream>
#include <conio.h>

#include <SDKUtil/CLUtil.hpp>
#include <SDKUtil/SDKBitMap.hpp>
#include "Particle_Const.h"

using namespace appsdk;
#define SAMPLE_VERSION "AMD-APP-SDK-v2.9 (1.1)"
#define GROUP_SIZE 256

class OpenCLManager
{

public:
	cl_double setupTime;                /**< time taken to setup OpenCL resources and building kernel */
	cl_double kernelTime;               /**< time taken to run kernel and read result back */

	cl_int status;

	cl_context context;                 /**< CL context */
	
	cl_device_id *devices;              /**< CL device list */
	cl_device_id device;

	cl_platform_id *platforms;
	cl_platform_id platform;
	cl_command_queue commandQueue;      /**< CL command queue */
	cl_program program;                 /**< CL program  */

	cl_kernel mKernel_MatchingDepth;                 /**< CL kernel */
	cl_kernel mKernel_MatchingDepthTex2D;

	cl_kernel mKernelReduction;

	cl_uint pixelSize;                  /**< Size of a pixel in BMP format> */
	cl_uint width;                      /**< Width of image */
	cl_uint height;                     /**< Height of image */

	size_t kernel2DWorkGroupSize;         /**< Group Size returned by kernel */
	size_t kernel3DWorkGroupSize;         /**< Group Size returned by kernel */

	int iterations;                     /**< Number of iterations for kernel execution */
	
	SDKDeviceInfo	deviceInfo;                    /**< Structure to store device information*/
	KernelWorkGroupInfo	kernelInfo;              /**< Structure to store kernel related info */

	SDKTimer    *sampleTimer;      /**< SDKTimer object */
	int timer;
	CLCommandArgs   *sampleArgs;   /**< CLCommand argument class */

	cl_mem observeDepthCL;
	cl_mem observeSkinCL;
	cl_mem renderedDepthCL;
	cl_mem resultCL;

	size_t global_work_size;

	float * outputImageData2D;       /**< Output from device for 2D copy*/
	double dResult;
	/* functions */
	OpenCLManager(void):outputImageData2D(NULL)
	{
		sampleArgs = new CLCommandArgs() ;
		sampleTimer = new SDKTimer();
		sampleArgs->sampleVerStr = SAMPLE_VERSION;
		width = SIZE_IMAGE_PARTICLE_WIDTH;
		height = SIZE_IMAGE_PARTICLE_HEIGHT;
		global_work_size = width*height;
	}

	~OpenCLManager(void){}

	int setupOCL();
	/*FOR SIMULATION*/
	int setupSimulatingKernel(GLuint depthBuf, GLuint skinBuf, GLuint renderBuf);
	int acquireObservePixel();

	/*FOR REAL DATA*/
	int setupMatchingKernel(GLuint renderBuf );
	int setObserve(cl_ushort * depthBuf, uchar * skinBuf, cl_ushort depthScale);

	int runCLKernel_GetDforSwarm_Pixels(std::vector<double> &measureResult);

	//int setupMatchingKernel_Tex2D(GLuint depthTex, GLuint skinTex, GLuint renderTex);
	//int runKernel_Tex2D_Swarm(std::vector<double> &measureResult);
	void clearAllBuffer();	
	float reductionNoneCLKernel(cl_mem inputMem,size_t arraySize);
	int calculateSumCL(cl_mem inputMem,size_t arraySize,std::vector<double>&sum);
};

#endif

